package com.icekrvams.air.versionchecker

import android.app.Activity
import android.app.Activity.RESULT_OK
import com.google.android.play.core.appupdate.AppUpdateInfo
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.android.play.core.install.model.ActivityResult
import com.google.android.play.core.install.model.AppUpdateType
import com.google.android.play.core.install.model.UpdateAvailability
import com.google.android.play.core.ktx.isImmediateUpdateAllowed
import com.icekrvams.air.appContext

/**
 * 详情请了解应用内更新（https://developer.android.com/guide/playcore/in-app-updates）。
 * 此工具类收窄了其用法，仅支持进行 IMMEDIATE 类型的更新，不支持相对应的灵活更新(Flexible)。
 */
object VersionUpdateManager {

    private const val INVALID_DAYS = -1

    private const val INTERNAL_REQUEST_CODE = 1107

    private val appUpdateManager = AppUpdateManagerFactory.create(appContext)

    /**
     * 是否存在可用的版本更新。
     */
    private fun AppUpdateInfo.isNewVersionAvailable(): Boolean {
        return this.updateAvailability() ==
                UpdateAvailability.UPDATE_AVAILABLE && this.isImmediateUpdateAllowed
    }

    /**
     * 判断是否可以进行版本更新。
     * @param versionUpdateCheckCallback 版本更新检查回调。
     */
    fun checkVersionUpdateInfo(versionUpdateCheckCallback: VersionUpdateCheckCallback) {
        appUpdateManager.appUpdateInfo.addOnSuccessListener { updateInfo ->
            // 只关心版本更新，不考虑灵活更新。
            val isVersionUpdateAvailable = updateInfo.isNewVersionAvailable()
            if (isVersionUpdateAvailable) {
                updateInfo.apply {
                    versionUpdateCheckCallback.onAvailable(
                        availableVersionCode(),
                        clientVersionStalenessDays() ?: INVALID_DAYS,
                        updatePriority(),
                        this
                    )
                }
            } else {
                versionUpdateCheckCallback.onUnavailable(updateInfo)
            }
        }.addOnFailureListener {
            versionUpdateCheckCallback.onFailure(it)
        }
    }

    /**
     * 启动更新流程。
     * @param appUpdateInfo 应用更新信息。
     * @param activity 用于启动 Intent 的 Activity，并且该 Activity 会收到 onActivityResult 回调。
     * @return 是否通过检查并启动更新流程。
     */
    fun launchUpdateFlowForResult(
        appUpdateInfo: AppUpdateInfo,
        activity: Activity,
    ): Boolean {
        // 不存在可用的新版本，直接返回。
        if (!appUpdateInfo.isNewVersionAvailable()) return false
        appUpdateManager.startUpdateFlowForResult(
            appUpdateInfo,
            AppUpdateType.IMMEDIATE,
            activity,
            INTERNAL_REQUEST_CODE
        )
        return true
    }

    /**
     * 在应用入口 Activity 的 onResume 方法调用，检查是否有尚未完成的更新，并继续完成更新。
     * @param activity 用于启动 Intent 的 Activity，并且该 Activity 会收到 onActivityResult 回调。
     */
    fun onResume(activity: Activity) {
        appUpdateManager.appUpdateInfo
            .addOnSuccessListener { updateInfo ->
                if (updateInfo.updateAvailability()
                    == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS
                ) {
                    appUpdateManager.startUpdateFlowForResult(
                        updateInfo,
                        AppUpdateType.IMMEDIATE,
                        activity,
                        INTERNAL_REQUEST_CODE
                    )
                }
            }
    }

    /**
     * 处理更新结果，在启动更新流程的 Activity#onActivityResult 方法中调用。
     * @param requestCode 请求码。
     * @param resultCode 结果码。
     * @param versionUpdateResultCallback 版本更新结果回调。
     */
    fun onActivityResult(
        requestCode: Int,
        resultCode: Int,
        versionUpdateResultCallback: VersionUpdateResultCallback
    ) {
        if (requestCode != INTERNAL_REQUEST_CODE) return
        when (resultCode) {
            RESULT_OK -> versionUpdateResultCallback.onAccepted()
            Activity.RESULT_CANCELED -> versionUpdateResultCallback.onCanceled()
            ActivityResult.RESULT_IN_APP_UPDATE_FAILED -> versionUpdateResultCallback.onFailure()
        }
    }

    interface VersionUpdateCheckCallback {
        /**
         *  请求成功，且存在可用的更新。
         *  @param versionCode 可用更新的版本号。
         *  @param daysOfTheVersion 自 Play 商店中提供更新以来已经过了多少天。
         *  @param updatePriority 更新优先级，0～5，值越大，优先级越高。
         *  @param appUpdateInfo 应用更新信息，包含上述参数，可用于启动更新。
         */
        fun onAvailable(
            versionCode: Int,
            daysOfTheVersion: Int,
            updatePriority: Int,
            appUpdateInfo: AppUpdateInfo
        )

        /**
         * 请求成功，但不存在可用的更新。
         *  @param appUpdateInfo 应用更新信息。
         */
        fun onUnavailable(appUpdateInfo: AppUpdateInfo) {}

        /**
         * 请求失败。
         */
        fun onFailure(e: Exception) {}
    }

    interface VersionUpdateResultCallback {

        /**
         * 并不是表示更新完成，而是具有以下含义：
         * 用户已接受更新。对于立即更新，您可能不会收到此回调，因为在将控制权交还给您的应用之前，更新应该已经完成了。
         */
        fun onAccepted() {}

        /**
         * 用户已拒绝或取消更新。
         */
        fun onCanceled() {}

        /**
         * 发生了一些其他错误，使得用户无法同意更新或更新无法继续进行。
         */
        fun onFailure() {}
    }
}